
package com.hlkj.pay.app.merchant.ext.impl.yytpay.ext;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import java.util.*;

import org.springframework.stereotype.Repository;

import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.framework.extension.annotation.Extension;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelPayOrderContext;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelPayOrderQueryContext;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelRefundPayOrderContext;
import com.hlkj.pay.app.merchant.ext.impl.yytpay.YytPayScenePayOrderExtPt;
import com.hlkj.pay.app.merchant.ext.impl.yytpay.constant.YytPayAppChannelParams;
import com.hlkj.pay.app.merchant.ext.impl.yytpay.constant.YytPayExtConstant;
import com.hlkj.pay.app.merchant.ext.impl.yytpay.dto.YytPayConfig;
import com.hlkj.pay.app.merchant.ext.impl.yytpay.dto.resp.YytOrderDataResp;
import com.hlkj.pay.app.merchant.ext.impl.yytpay.dto.resp.YytOrderPreDataResp;
import com.hlkj.pay.app.merchant.ext.impl.yytpay.dto.resp.YytOrderResp;
import com.hlkj.pay.app.merchant.ext.impl.yytpay.handler.YytPayCommonParamsHandle;
import com.hlkj.pay.enums.PayEnums;
import com.hlkj.pay.infrastructure.model.merchant.MerchantAppChannelDO;
import com.hlkj.pay.infrastructure.model.order.PayOrderDO;
import com.hlkj.pay.infrastructure.model.pay.PayWayDO;
import com.hlkj.pay.vo.order.req.PayOrderCommonParamReq;

import cn.hutool.core.net.url.UrlQuery;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 公众号统一下单
 *
 * @author HlpayTeam
 * @date 2024/11/18 13:07
 */
@Slf4j
@Repository
@RequiredArgsConstructor
@Extension(bizId = YytPayExtConstant.MINI_APP)
public class YytPayMiniPayOrderExtPt extends YytPaySceneCommonPayOrder implements YytPayScenePayOrderExtPt {

    private final YytPayCommonParamsHandle yytPayCommonParamsHandle;

    @Override
    public void submitChannelPayOrder(ChannelPayOrderContext channelPayOrderContext) {

        log.info("银盈通 MINI 请求参数:{}", JsonUtils.toJsonString(channelPayOrderContext));
        CommonResult<YytPayConfig> lyytPayConfigCommonResult = yytPayCommonParamsHandle.yytPayConfig(channelPayOrderContext.getProviderChannelConfigDO(),
                channelPayOrderContext.isTest());
        if (!lyytPayConfigCommonResult.isSuccess()) {
            channelPayOrderContext.setRemark(lyytPayConfigCommonResult.getMsg());
            channelPayOrderContext.setProcessStatus(false);
            return;
        }
        // 支付订单信息
        PayOrderDO payOrderDO = channelPayOrderContext.getPayOrderDO();
        // 支付方式信息
        PayWayDO payWayDO = channelPayOrderContext.getPayWayDO();
        // 商户通道信息
        MerchantAppChannelDO merchantAppChannelDO = channelPayOrderContext.getMerchantAppChannelDO();
        // 银盈通配置信息
        YytPayConfig yytPayConfig = lyytPayConfigCommonResult.getData();
        // 支付方式
        PayEnums.PAY_TYPE payType =  PayEnums.PAY_TYPE.fromByCode(payWayDO.getType());
        // 支付渠道枚举
        PayEnums.SCENE_PAY_TYPE scenePayType = PayEnums.SCENE_PAY_TYPE.from(payWayDO.getSubType());
        // 额外参数信息
        PayOrderCommonParamReq.Extra extra = channelPayOrderContext.getExtra();
        // if (extra == null || !StringUtils.hasText(extra.getUserId())) {
        //     channelPayOrderContext.setProcessStatus(Boolean.FALSE);
        //     channelPayOrderContext.setRemark("银盈通 "+payType.getType() +" 提交 MINI 支付 没有提交userId");
        //     return;
        // }
        try {
            YytPayAppChannelParams yytAppChannelParams = JsonUtils.parseObject(merchantAppChannelDO.getAppConfigJson(), YytPayAppChannelParams.class);

            String payway = yytPayCommonParamsHandle.getPayWay(payWayDO);
            if(StrUtil.isEmpty(payway)){
                channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                channelPayOrderContext.setRemark("银盈通提交 MINI支付 支付类型: "+payWayDO.getType()+" 不支持");
                return;
            }

            String getPayChannel = yytPayCommonParamsHandle.getPayChannel(payWayDO);
            if(StrUtil.isEmpty(getPayChannel)){
                channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                channelPayOrderContext.setRemark("银盈通提交 MINI支付 渠道类型: "+payWayDO.getType()+" 不支持");
                return;
            }

            // 预下单接口
            Map<String, Object> dataMap = new HashMap<>();
            dataMap.put("order_number", payOrderDO.getPayOrderNo());
            dataMap.put("notify_url", channelPayOrderContext.getNotifyUrl());
            dataMap.put("merchant_number", yytAppChannelParams.getMchId());
            dataMap.put("scene", "14");
            dataMap.put("total_amount", NumberUtil.roundStr(payOrderDO.getAmount().doubleValue(),2));
            dataMap.put("user_id", yytPayConfig.getUserId());
            dataMap.put("currency", "CNY");
            dataMap.put("good_desc", payOrderDO.getSubject());

            // AT 轮询数组  判断是否开启轮询
            String polling =  yytPayCommonParamsHandle.getAddService(yytPayConfig);
            if("1".equals(polling)){
                List<Map<String, Object>> channel_merch_info = new ArrayList<>();
                Map<String, Object> payInfo = new HashMap<>();
                payInfo.put("pay_type",payway);
                payInfo.put("channel_merch_no",yytPayCommonParamsHandle.getMchAtId(merchantAppChannelDO.getSubMchId(),payType));
                channel_merch_info.add(payInfo);
                dataMap.put("channel_merch_info",channel_merch_info);
            }

            log.info("银盈通提交MINI支付 预下单请求参数:{}", JSONUtil.toJsonStr(dataMap));
            YytOrderResp response = yytPayCommonParamsHandle.sendPostRequest("https://gc-gw.gomepay.com/gpayCashApi", JSONUtil.toJsonStr(dataMap), "cash-api@gcash.trade.precreate",yytPayConfig,payOrderDO,"4",payway);
            log.info("银盈通提交MINI支付 预下单返回参数:{}", response);
            if(response == null || !"000000".equals(response.getCode())) {
                channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                channelPayOrderContext.setRemark(response.getMsg());
                return;
            }
            // 预下单返回参数
            YytOrderPreDataResp preDataResp = JSONUtil.toBean(response.getData(),YytOrderPreDataResp.class);
            if(preDataResp == null || StrUtil.isEmpty(preDataResp.getOrder_id())){
                channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                channelPayOrderContext.setRemark("银盈通提交MINI支付 预下单返回参数错误");
                return;
            }

            // 支付接口
            Map<String,Object> reqData = new HashMap<>();
            reqData.put("order_id",preDataResp.getOrder_id());
            reqData.put("merchant_number",preDataResp.getMerchant_number());
            reqData.put("order_number",payOrderDO.getPayOrderNo());
            reqData.put("total_amount",NumberUtil.roundStr(payOrderDO.getAmount().doubleValue(),2));
            reqData.put("receipt_amount",NumberUtil.roundStr(payOrderDO.getAmount().doubleValue(),2));


            List<Map<String,Object>> r_data = new ArrayList<>();
            Map<String,Object> data = new HashMap<>();
            data.put("pay_type", payway);
            data.put("channel_code",getPayChannel);
            data.put("pay_amount",NumberUtil.roundStr(payOrderDO.getAmount().doubleValue(),2));
            data.put("discount_amount","0");
            data.put("interface_type",yytPayCommonParamsHandle.getInterfaceType(payWayDO));
            data.put("biz_id",preDataResp.getUser_id());
            r_data.add(data);
            reqData.put("r_data",r_data);

            log.info("银盈通提交MINI支付 支付请求参数:{}", JSONUtil.toJsonStr(reqData));
            YytOrderResp result = yytPayCommonParamsHandle.sendPostRequest("https://gc-gw.gomepay.com/gpayCashApi", JSONUtil.toJsonStr(reqData), "cash-api@gcash.trade.pay",yytPayConfig,payOrderDO,"4",payway);
            log.info("银盈通提交MINI支付 支付返回参数:{}", JSONUtil.toJsonStr(result));
            if(result == null ||!"900888".equals(result.getCode())) {
                channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                channelPayOrderContext.setRemark(result.getMsg());
                return;
            }
            // 结果转对象
            YytOrderDataResp MINIPayRes = JSONUtil.toBean(result.getData(),YytOrderDataResp.class);
            // 900888+bank_order_id 代表成功
            if(MINIPayRes == null || StrUtil.isEmpty(MINIPayRes.getBank_order_id())){
                channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                channelPayOrderContext.setRemark("bank_order_id is null");
                return;
            }
            // 通信状态和支付状态都成功
            channelPayOrderContext.setInsOrderNo(MINIPayRes.getOrder_id());
            channelPayOrderContext.setChannelOrderNo(MINIPayRes.getBank_order_id());

            String h5Path = null;
            String appPath = null;
            Map<String,Object> payInfodata = new LinkedHashMap<>();
            switch (payType){
                case WECHAT:
                    // 生成H5链接
                    Map<String,Object> reqdata = new LinkedHashMap<>();
                    reqdata.put("appid",yytPayConfig.getYytAppId());
                    reqdata.put("path", "pages/wechat/preOrder/orderpay");
                    Map<String,String> query = new HashMap<>();
                    query.put("orderId",MINIPayRes.getBank_order_id());
                    query.put("env","h5");

                    String queryStr = StrUtil.replace(URLUtil.buildQuery(query, CharsetUtil.CHARSET_UTF_8),"&","%26");
                    reqdata.put("query",  StrUtil.replace(queryStr,"=","%3D") );
                    reqdata.put("env_version","release");

                    // 编码查询参数并拼接成查询字符串
                    h5Path = "weixin://dl/business/?"+UrlQuery.of(reqdata);
                    // 生成APP链接
                    appPath = "pages/wechat/preOrder/orderpay?orderId="+MINIPayRes.getBank_order_id()+"&env=app";


                    payInfodata.put("userName",yytPayConfig.getYytMiniId());
                    payInfodata.put("path",appPath);
                    payInfodata.put("schemeCode",h5Path);

                    break;
                case ALIPAY:
                    String env= null;
                    switch (scenePayType){
                        case APP:
                            env = "app";
                            break;
                        case H5:
                            env = "h5";
                            break;
                        default:
                            channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                            channelPayOrderContext.setRemark("银盈通提交 MINI支付 支付方式: "+scenePayType.getType()+" 不支持");
                            return;
                    }
                    h5Path = "https://h5.gomepay.com/cashier-h5/index.html#/pages/preOrder/orderPay?orderId="+MINIPayRes.getBank_order_id()+"&env="+env;
                    appPath = h5Path;
                    payInfodata.put("userName","");
                    payInfodata.put("path",appPath);
                    payInfodata.put("schemeCode",h5Path);
                    break;
            }

            log.info("银盈通提交MINI支付 返回PayInfo封装参数:{}", JSONUtil.toJsonStr(payInfodata));

            channelPayOrderContext.setPayDataType("data");
            channelPayOrderContext.setPayInfo(JSONUtil.toJsonStr(payInfodata));
        }catch (Exception e) {
            log.error("银盈通提交MINI支付 请求失败, error: {}",e);
            channelPayOrderContext.setRemark("银盈通提交MINI支付 请求失败, error: " + e.getMessage());
            channelPayOrderContext.setProcessStatus(Boolean.FALSE);
        }
    }

    @Override
    public void queryChannelPayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        commonQueryChannelPayOrder(channelPayOrderQueryContext);
    }

    @Override
    public void closeChannelPayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        commonCloseChannelPayOrder(channelPayOrderQueryContext);
    }

    @Override
    public void queryChannelClosePayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        commonQueryChannelClosePayOrder(channelPayOrderQueryContext);
    }

    @Override
    public void refundChannelPayOrder(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        commonRefundChannelPayOrder(channelRefundPayOrderContext);
    }

    @Override
    public void queryRefundChannelPayOrder(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        commonQueryRefundChannelPayOrder(channelRefundPayOrderContext);
    }

    @Override
    public boolean refundApply(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        return true;
    }

    @Override
    public CommonResult<String> channelOrderCode(ChannelPayOrderContext channelPayOrderContext) {
        return CommonResult.success();
    }
}
